#include<iostream>
#include<string>
#include<bitset>
#include<chrono>
using namespace std;
string sbox[16][16] = {
{"D6","90","E9","FE","CC","E1","3D","B7","16","B6","14","C2","28","FB","2C","05"},
{"2B","67","9A","76","2A","BE","04","C3","AA","44","13","26","49","86","06","99"},
{"9C","42","50","F4","91","EF","98","7A","33","54","0B","43","ED","CF","AC","62"},
{"EA","B3","1C","A9","C9","08","E8","95","80","DF","94","FA","75","8F","3F","A6"},
{"47","07","A7","FC","F3","73","17","BA","83","59","3C","19","E6","85","4F","A8"},
{"68","6B","8E","B2","71","64","DA","8B","F8","EB","0F","4B","70","56","9D","35"},
{"1E","24","OE","5E","63","58","D1","A2","25","22" "7C","3B","01","21","78","87"},
{"D4","00","46","57","9F","D3","27","52","4C","36","02","E7","AO","C4","C8","9E"},
{"EA","BF","8A","D2","40","C7","38","B5","A3","F7","F2","CE","F9","61","15","A1"},
{"E0","AE","5D","A4","9B","34","1A","55","AD","93","32","30","F5","8C","B1","E3"},
{"1D","F6","E2","2E","82","66","CA","60","C0","29","23","AB","OD","53","4E","6F"},
{"D5","DB","37","45","DE","FD","8E","2F","03","FF","6A","72","6D","6C","5B","51"},
{"8D","1B","AF","92","BB","DD","BC","7F","11","D9","5C","41","1F","10","5A","D8"},
{"0A","C1","31","88","A5","CD","7B","BD","2D","74","D0","12","B8","E5","B4","B0"},
{"89","69","97","4A","0C","96","77","7E","65","B9","F1","09","C5","6E","C6","84"},
{"18","F0","7D","EC","3A","DC","4D","20","79","EE","5F","3E","D7","CB","39","48"}
};
string ck[32] = { "00070e15","1c232a31","383f464d","545b6269","70777e85","8c939aa1","a8afb6bd",
"c4cbd2d9","e0e7eef5","fc030a11","181f262d","343b4249","50575e65","6c737a81","888f969d",
"a4abb2b9","c0c7ced5", "dce3eaf1","f8ff060d","141b2229","30373e45","4c535a61","686f767d",
"848b9299","a0a7aeb5","bcc3cad1","d8dfe6ed","f4fb0209","10171e25","2c333a41","484f565d","646b7279" };
string fk[4] = { "A3B1BAC6","56AA3350","677D9197","B27022DC" };

bitset<128> change_bin_128bit(string a)
{
	int len = a.length();
	string b;
	for (int i = 0; i < len; i++)
	{
		if (a[i] == '0')
		{
			b.append("0000");
		}
		else if (a[i] == '1')
		{
			b.append("0001");
		}
		else if (a[i] == '2')
		{
			b.append("0010");
		}
		else if (a[i] == '3')
		{
			b.append("0011");
		}
		else if (a[i] == '4')
		{
			b.append("0100");
		}
		else if (a[i] == '5')
		{
			b.append("0101");
		}
		else if (a[i] == '6')
		{
			b.append("0110");
		}
		else if (a[i] == '7')
		{
			b.append("0111");
		}
		else if (a[i] == '8')
		{
			b.append("1000");
		}
		else if (a[i] == '9')
		{
			b.append("1001");
		}
		else if (a[i] == 'a' || a[i] == 'A')
		{
			b.append("1010");
		}
		else if (a[i] == 'b' || a[i] == 'B')
		{
			b.append("1011");
		}
		else if (a[i] == 'c' || a[i] == 'C')
		{
			b.append("1100");
		}
		else if (a[i] == 'd' || a[i] == 'D')
		{
			b.append("1101");
		}
		else if (a[i] == 'e' || a[i] == 'E')
		{
			b.append("1110");
		}
		else if (a[i] == 'f' || a[i] == 'F')
		{
			b.append("1111");
		}
	}
	bitset<128> re(b);
	return re;
}
bitset<32> change_bin(string a)
{
	int len = a.length();
	string b;
	for (int i = 0; i < len; i++)
	{
		if (a[i] == '0')
		{
			b.append("0000");
		}
		else if (a[i] == '1')
		{
			b.append("0001");
		}
		else if (a[i] == '2')
		{
			b.append("0010");
		}
		else if (a[i] == '3')
		{
			b.append("0011");
		}
		else if (a[i] == '4')
		{
			b.append("0100");
		}
		else if (a[i] == '5')
		{
			b.append("0101");
		}
		else if (a[i] == '6')
		{
			b.append("0110");
		}
		else if (a[i] == '7')
		{
			b.append("0111");
		}
		else if (a[i] == '8')
		{
			b.append("1000");
		}
		else if (a[i] == '9')
		{
			b.append("1001");
		}
		else if (a[i] == 'a' || a[i] == 'A')
		{
			b.append("1010");
		}
		else if (a[i] == 'b' || a[i] == 'B')
		{
			b.append("1011");
		}
		else if (a[i] == 'c' || a[i] == 'C')
		{
			b.append("1100");
		}
		else if (a[i] == 'd' || a[i] == 'D')
		{
			b.append("1101");
		}
		else if (a[i] == 'e' || a[i] == 'E')
		{
			b.append("1110");
		}
		else if (a[i] == 'f' || a[i] == 'F')
		{
			b.append("1111");
		}
	}
	bitset<32> re(b);
	return re;
}
bitset<32> change_bitset(string a)
{
	bitset<32> re(a);
	return re;
}
string change_hex(bitset<128> word)
{
	string w;
	w=word.to_string();
	string re;
	int len = w.length();
	for (int i = 0; i < len; i = i + 4)
	{
		string temp;
		temp = w.substr(i, 4);
		if (temp == "0000")
		{
			re.append("0");
		}
		else if(temp == "0001")
		{
			re.append("1");
		}
		else if (temp == "0010")
		{
			re.append("2");
		}
		else if (temp == "0011")
		{
			re.append("3");
		}
		else if (temp == "0100")
		{
			re.append("4");
		}
		else if (temp == "0101")
		{
			re.append("5");
		}
		else if (temp == "0110")
		{
			re.append("6");
		}
		else if (temp == "0111")
		{
			re.append("7");
		}
		else if (temp == "1000")
		{
			re.append("8");
		}
		else if (temp == "1001")
		{
			re.append("9");
		}
		else if (temp == "1010")
		{
			re.append("a");
		}
		else if (temp == "1011")
		{
			re.append("b");
		}
		else if (temp == "1100")
		{
			re.append("c");
		}
		else if (temp == "1101")
		{
			re.append("d");
		}
		else if (temp == "1110")
		{
			re.append("e");
		}
		else if (temp == "1111")
		{
			re.append("f");
		}
	}
	return re;
}
bitset<8> change_bin_s_box(string a)
{
	int len = a.length();
	string b;
	for (int i = 0; i < len; i++)
	{
		if (a[i] == '0')
		{
			b.append("0000");
		}
		else if (a[i] == '1')
		{
			b.append("0001");
		}
		else if (a[i] == '2')
		{
			b.append("0010");
		}
		else if (a[i] == '3')
		{
			b.append("0011");
		}
		else if (a[i] == '4')
		{
			b.append("0100");
		}
		else if (a[i] == '5')
		{
			b.append("0101");
		}
		else if (a[i] == '6')
		{
			b.append("0110");
		}
		else if (a[i] == '7')
		{
			b.append("0111");
		}
		else if (a[i] == '8')
		{
			b.append("1000");
		}
		else if (a[i] == '9')
		{
			b.append("1001");
		}
		else if (a[i] == 'a' || a[i] == 'A')
		{
			b.append("1010");
		}
		else if (a[i] == 'b' || a[i] == 'B')
		{
			b.append("1011");
		}
		else if (a[i] == 'c' || a[i] == 'C')
		{
			b.append("1100");
		}
		else if (a[i] == 'd' || a[i] == 'D')
		{
			b.append("1101");
		}
		else if (a[i] == 'e' || a[i] == 'E')
		{
			b.append("1110");
		}
		else if (a[i] == 'f' || a[i] == 'F')
		{
			b.append("1111");
		}
	}
	bitset<8> re(b);
	return re;
}
int get_row(string a)
{
	string tmp = a.substr(0, 4);
	bitset<4> x(tmp);
	int re =x.to_ullong();
	return re;
}
int get_col(string a)
{
	string tmp = a.substr(4, 4);
	bitset<4> x(tmp);
	int re = x.to_ullong();
	return re;
}
bitset<32> shift_left(bitset<32> a,int time)
{
	string s = a.to_string();
	char tmp;
	for (int i = 0; i < time; i++)
	{
		tmp = s[0];
		for (int j = 0; j < 31; j++)
		{
			s[j] = s[j + 1];
		}
		s[31] = tmp;
	}
	bitset<32> re(s);
	return re;
}
bitset<8> s_box(string a)//a is 8 bit
{
	int row = get_row(a);
	int col = get_col(a);
	string temp = sbox[row][col];
	bitset<8> re = change_bin_s_box(temp);
	return re;
}
bitset<32> L(bitset<32> B)
{
	bitset<32> re1 = shift_left(B, 2);
	bitset<32> re2 = shift_left(B, 10);
	bitset<32> re3 = shift_left(B, 18);
	bitset<32> re4 = shift_left(B, 24);
	bitset<32> re = B ^ re1 ^ re2 ^ re3 ^ re4;
	return re;
}
bitset<32> T(bitset<32> A)
{
	string tmp = A.to_string();//tmp is bin 32 bit
	string a[4];
	a[0] = tmp.substr(0, 8);
	a[1] = tmp.substr(8, 8);
	a[2] = tmp.substr(16, 8);
	a[3] = tmp.substr(24, 8);
	bitset<8> b[4];
	for (int i = 0; i < 4; i++)
	{
		b[i] = s_box(a[i]);
	}
	bitset<32> B;
	for (int j=0; j < 8; j++)
	{
		B[j] = b[3][j];
	}
	for (int j = 0; j < 8; j++)
	{
		B[8 + j] = b[2][j];
	}
	for (int j = 0; j < 8; j++)
	{
		B[16 + j] = b[1][j];
	}
	for (int j = 0; j < 8; j++)
	{
		B[24 + j] = b[0][j];
	}
	bitset<32> re;
	re = L(B);
	return re;
}
bitset<32> L_key(bitset<32> B)
{
	bitset<32> re1 = shift_left(B, 13);
	bitset<32> re2 = shift_left(B, 23);
	bitset<32> re = B ^ re1 ^ re2;
	return re;
}
bitset<32> T_key(bitset<32> A)
{
	string tmp = A.to_string();//tmp is bin 32 bit
	string a[4];
	a[0] = tmp.substr(0, 8);
	a[1] = tmp.substr(8, 8);
	a[2] = tmp.substr(16, 8);
	a[3] = tmp.substr(24, 8);
	bitset<8> b[4];
	for (int i = 0; i < 4; i++)
	{
		b[i] = s_box(a[i]);
	}
	bitset<32> B;
	for (int j = 0; j < 8; j++)
	{
		B[j] = b[3][j];
	}
	for (int j = 0; j < 8; j++)
	{
		B[8 + j] = b[2][j];
	}
	for (int j = 0; j < 8; j++)
	{
		B[16 + j] = b[1][j];
	}
	for (int j = 0; j < 8; j++)
	{
		B[24 + j] = b[0][j];
	}
	bitset<32> re;
	re = L_key(B);
	return re;
}
bitset<128> one_encryption(bitset<128> a,bitset<32> rk)//a is bin 128bit
{
	string tmp = a.to_string();
	string x[4];
	x[0] = tmp.substr(0, 32);
	x[1] = tmp.substr(32, 32);
	x[2] = tmp.substr(64, 32);
	x[3] = tmp.substr(96, 32);
	bitset<32> temp[4];
	for (int i = 0; i < 4; i++)
	{
		temp[i] = change_bitset(x[i]);
	}
	bitset<32> re = temp[1] ^ temp[2] ^ temp[3] ^ rk;
	bitset<32> T_re = T(re);
	bitset<32> y[4];
	y[3]=temp[0] ^ T_re;
	y[2] = temp[3];
	y[1] = temp[2];
	y[0] = temp[1];
	string k[4];
	string Re;
	for (int i = 0; i < 4; i++)
	{
		k[i] = y[i].to_string();
	}
	for (int i = 0; i < 4; i++)
	{
		Re.append(k[i]);
	}
	bitset<128> RE(Re);
	return RE;
}
bitset<32>* gen_keys(string mk)//mk 128bit
{
	bitset<32>* rkeys = new bitset<32>[32];
	string Mk[4];
	Mk[0] = mk.substr(0, 32);
	Mk[1] = mk.substr(32, 32);
	Mk[2] = mk.substr(64, 32);
	Mk[3] = mk.substr(96, 32);
	bitset<32> MK[4];
	for (int i = 0; i < 4; i++)
	{
		MK[i] = change_bitset(Mk[i]);
	}
	bitset<32> FK[4];
	for (int i = 0; i < 4; i++)
	{
		FK[i] = change_bin(fk[i]);
	}
	bitset<32> CK[32];
	for (int i = 0; i < 32; i++)
	{
		CK[i] = change_bin(ck[i]);
	}
	bitset<32> K[36];
	for (int i = 0; i < 4; i++)
	{
		K[i] = MK[i] ^ FK[i];
	}
	for (int i = 0; i < 28; i++)
	{
		K[i + 4] = K[i] ^ T_key(K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i]);
		rkeys[i] = K[i + 4];
	}
	rkeys[28] = K[32] = K[28] ^ T_key(K[29] ^ K[30] ^ K[31] ^ CK[28]);
	rkeys[29] = K[33] = K[29] ^ T_key(K[30] ^ K[31] ^ K[32] ^ CK[29]);
	rkeys[30] = K[34] = K[30] ^ T_key(K[31] ^ K[32] ^ K[33] ^ CK[30]);
	rkeys[31] = K[31] ^ T_key(K[32] ^ K[33] ^ K[34] ^ CK[31]);
	return rkeys;
}
bitset<128> encryption(string word, string key)//word and key is hex(128bit)
{
	bitset<128> plaintext = change_bin_128bit(word);
	bitset<128> keyy = change_bin_128bit(key);//ѾתΪ128bit
	string k = keyy.to_string();
	bitset<32>* rk=new bitset<32> [32];
	bitset<128>* tmp = new bitset<128>[32];
	rk=gen_keys(k);
	tmp[0] = plaintext;
	for (int i = 0; i < 31; i++)
	{
		tmp[i + 1] = one_encryption(tmp[i], rk[i]);
	}
	bitset<128> re;
	re = one_encryption(tmp[31], rk[31]);
	string Re;
	Re = re.to_string();
	string RE;
	RE.append(Re.substr(96,32));
	RE.append(Re.substr(64, 32));
	RE.append(Re.substr(32, 32));
	RE.append(Re.substr(0, 32));
	bitset<128> ree(RE);
	return ree;
}
bitset<128> decryption(string word, string key)
{
	bitset<128> ciphertext = change_bin_128bit(word);
	bitset<128> keyy = change_bin_128bit(key);
	string k = keyy.to_string();
	bitset<32>* rk = new bitset<32>[32];
	bitset<128>* tmp = new bitset<128>[32];
	rk = gen_keys(k);
	tmp[0] = ciphertext;
	for (int i = 0; i < 31; i++)
	{
		tmp[i + 1] = one_encryption(tmp[i],rk[31-i]);
	}
	bitset<128> re;
	re = one_encryption(tmp[31], rk[0]);
	string Re;
	Re = re.to_string();
	string RE;
	RE.append(Re.substr(96, 32));
	RE.append(Re.substr(64, 32));
	RE.append(Re.substr(32, 32));
	RE.append(Re.substr(0, 32));
	bitset<128> ree(RE);
	return ree;
}

int main()
{
	string plaintext; //= "ef1212123434565678789090ababcdcd";
	cout << "Enter the plaintext (16byte):";
	cin >> plaintext;
	string key; //="01ab01ab01ab01ab01ab01ab01ab01ab";
	cout << "Enter the key(16byte):";
	cin >> key;
	bitset<128> re;
	auto start = std::chrono::high_resolution_clock::now();
	re = encryption(plaintext, key);
	auto end = std::chrono::high_resolution_clock::now();
	std::chrono::duration<double, std::ratio<1, 1000>>result = end - start;
	string x = change_hex(re);
	cout <<"The text after encryption:" << x << endl;
	cout << "The encryption cost time:" << result<<endl;
	bitset<128> ree;
	auto start = std::chrono::high_resolution_clock::now();
	ree = decryption(x, key);
	string y = change_hex(ree);
	auto end = std::chrono::high_resolution_clock::now();
	std::chrono::duration<double, std::ratio<1, 1000>>result = end - start;
	cout << "The text after decryption:"<<y << endl;
	cout << "The decryption cost time:" << result<<endl;
} 